//-------------------------------------------------------------
#include <stdio.h>
#include <string>
#include <algorithm>
namespace tt01
{
using namespace std;
class ResourceOwner {
public:
  ResourceOwner(const char res[]) {
    theResource = new string(res);
  }

  ResourceOwner(const ResourceOwner& other) {
    printf("copy %s\n", other.theResource->c_str());
    theResource = new string(other.theResource->c_str());
  }

  ResourceOwner& operator=(const ResourceOwner& other) {
    ResourceOwner tmp(other);
    swap(theResource, tmp.theResource);
    printf("assign %s\n", other.theResource->c_str());
    return *this;
  }

  ~ResourceOwner() {
    if (theResource) {
      printf("destructor %s\n", theResource->c_str());
      delete theResource;
    }
  }
    
private:
  string* theResource;
};

    void testCopy() {
    // case 1
    printf("=====start testCopy()=====\n");
    ResourceOwner res1("res1");
    //拷贝构造
    ResourceOwner res2 = res1;
    //copy res1
    printf("=====destructors for stack vars, ignore=====\n");
    }

    void testAssign() {
    // case 2
    printf("=====start testAssign()=====\n");
    ResourceOwner res1("res1");
    ResourceOwner res2("res2");
    //拷贝赋值
    res2 = res1;
    //copy res1, assign res1, destrctor res2
    printf("=====destructors for stack vars, ignore=====\n");
    }

    void testRValue() {
    // case 3
    printf("=====start testRValue()=====\n");
    ResourceOwner res2("res2");
    res2 = ResourceOwner("res1");
    //copy res1, assign res1, destructor res2, destructor res1
    printf("=====destructors for stack vars, ignore=====\n");
    }

} //namespace
//-------------------------------------------------------------


//-------------------------------------------------------------
//使用&&，避免右值深拷贝
//右值是一个 构造函数或赋值函数的参数， 对应的类包含了指针(委托了一个资源)，指向一个动态分配的资源（内存）时
//避免 深拷贝, 只需要将指针指向那个位置就行了
#include <stdio.h>
#include <string>
#include <algorithm>
namespace tt02{

using namespace std;
class ResourceOwner {
public:
  ResourceOwner(const char res[]) {
    theResource = new string(res);
  }

  ResourceOwner(const ResourceOwner& other) {
    printf("copy %s\n", other.theResource->c_str());
    theResource = new string(other.theResource->c_str());
  }

  ResourceOwner& operator=(const ResourceOwner& other) {
    ResourceOwner tmp(other);
    swap(theResource, tmp.theResource);
    printf("assign %s\n", other.theResource->c_str());
    return *this;
  }

  //&&区分右值，避免深拷贝。
  //右值是一个 构造函数或赋值函数的参数， 对应的类包含了指针(委托了一个资源)，指向一个动态分配的资源（内存）时
  //避免 深拷贝, 只需要将指针指向那个位置就行了
  ResourceOwner& operator=(ResourceOwner&& other) {
    //自我检测
    if(this == &other){
        return *this;
    }
    delete theResource;
    theResource = other.theResource;
    other.theResource = NULL;
    return *this;
}

  ~ResourceOwner() {
    if (theResource) {
      printf("destructor %s\n", theResource->c_str());
      delete theResource;
    }
  }
    
private:
  string* theResource;
};

    void testRValue() {
    // case 3
    printf("=====start testRValue()=====\n");
    ResourceOwner res2("res2");
    res2 = ResourceOwner("res1");
    //copy res1, assign res1, destructor res2, destructor res1
    printf("=====destructors for stack vars, ignore=====\n");
    }

} //namespace
//-------------------------------------------------------------




//-------------------------------------------------------------
//测试右值引用失效场景
//tt04将引出解决方案
//C++中的万能引用和完美转发 https://theonegis.github.io/cxx/C-%E4%B8%AD%E7%9A%84%E4%B8%87%E8%83%BD%E5%BC%95%E7%94%A8%E5%92%8C%E5%AE%8C%E7%BE%8E%E8%BD%AC%E5%8F%91/

#include <iostream>
using std::cout;
using std::endl;

namespace tt03{


    template<typename T>
    void func(T& param) {
        cout << "传入的是左值" << endl;
    }

    template<typename T>
    void func(T&& param) {
        cout << "传入的是右值" << endl;
    }

    template<typename T>
    void warp(T&& param) {
        func(param);
    }

    void test_forward() {
        int num = 2019;
        warp(num);  //左值
        warp(2019); //右值 
    }
} //namespace
//-------------------------------------------------------------


//-------------------------------------------------------------
//测试右值引用失效场景
//tt04将引出解决方案 std::forward 完美转发,函数调用过程中，变量类型的不变
//C++中的万能引用和完美转发 https://theonegis.github.io/cxx/C-%E4%B8%AD%E7%9A%84%E4%B8%87%E8%83%BD%E5%BC%95%E7%94%A8%E5%92%8C%E5%AE%8C%E7%BE%8E%E8%BD%AC%E5%8F%91/
//&& 在模板参数类型 或auto推导 时，即可传左值也可传右值，万能引用
#include <iostream>
using std::cout;
using std::endl;

namespace tt04{


    template<typename T>
    void func(T& param) {
        cout << "传入的是左值" << endl;
    }

    template<typename T>
    void func(T&& param) {
        cout << "传入的是右值" << endl;
    }

    template<typename T>
    void warp(T&& param) {
        func(std::forward<T>(param));
    }

    void test_forward() {
        int num = 2019;
        warp(num);  //左值
        warp(2019); //右值 
    }
} //namespace
//-------------------------------------------------------------














int main() {
    tt01::testCopy();  printf("\n\n");
    tt01::testAssign();printf("\n\n");
    tt01::testRValue();printf("\n\n");


    tt02::testRValue();printf("\n\n");

    tt03::test_forward();printf("\n\n");

    tt04::test_forward();printf("\n\n");
}

